package walletuserslogic

import (
	"context"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go.uber.org/zap"
	"navi-mumbai/app/rpc/model/pg/wallet"
	"navi-mumbai/common/key/dbkey"
	"navi-mumbai/common/key/walletkey"
	"navi-mumbai/common/uniqueid"
	"navi-mumbai/common/utils"
	"navi-mumbai/common/xerr"

	"navi-mumbai/app/rpc/wallet/internal/svc"
	"navi-mumbai/app/rpc/wallet/pb"

	"github.com/zeromicro/go-zero/core/logx"
)

type UserCreateTransferToGameLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUserCreateTransferToGameLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserCreateTransferToGameLogic {
	return &UserCreateTransferToGameLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// 创建转出B端钱包
func (l *UserCreateTransferToGameLogic) UserCreateTransferToGame(in *pb.UserCreateTransferToGameReq) (*pb.UserCreateTransferToGameResp, error) {
	defer utils.RecoverPanic()

	var err error
	// 检查用户钱包是否存在
	var uw *wallet.UserWallet
	uw, err = l.svcCtx.UserWalletModel.FindOneByUidMoneyType(l.ctx, in.Uid, in.MoneyType)
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		if err == wallet.ErrNotFound {
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletNotFound, "wallet not exist")
		}
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, err.Error())
	}

	// 检查用户钱包余额是否足够
	// 转出金额
	var dOutMoneyAmount decimal.Decimal
	// 钱包余额
	var dUwMoneyAmount = decimal.NewFromInt(uw.Amount)
	if in.MoneyAmount != "0" {
		dOutMoneyAmount, err = decimal.NewFromString(in.MoneyAmount)
		if err != nil {
			l.Logger.Errorf("err == ", zap.Error(err))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "invalid param")
		}
		dOutMoneyAmount = dOutMoneyAmount.Mul(decimal.NewFromFloat(walletkey.MoneyScale))
		if dOutMoneyAmount.GreaterThan(dUwMoneyAmount) {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletBalanceNotEnoughForTransfer, "wallet balance not enough")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletBalanceNotEnoughForTransfer, "wallet balance not enough")
		}
	} else if in.MoneyAmount == "0" { // 全部转出
		if dUwMoneyAmount.LessThanOrEqual(decimal.Zero) {
			l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.WalletBalanceNotEnoughForTransfer, "wallet balance not enough")))
			return nil, xerr.NewGrpcErrCodeMsg(xerr.WalletBalanceNotEnoughForTransfer, "wallet balance not enough")
		}
		dOutMoneyAmount = dUwMoneyAmount
	} else {
		l.Logger.Errorf("err == ", zap.Error(xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "invalid param")))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.RequestParamError, "invalid param")
	}

	iOutMoneyAmount := dOutMoneyAmount.IntPart()

	// 创建转账到G流水
	var utf = wallet.UserTransferToGameFlow{
		FlowNo:      uniqueid.GenFlowNoX(),
		Uid:         in.Uid,
		MoneyType:   in.MoneyType,
		MoneyAmount: iOutMoneyAmount,
		ProviderId:  in.ProviderId,
		State:       walletkey.UserWalletTransferToGameFlowStateInit,
	}

	// 查询用户游戏钱包
	var ugw *wallet.UserGameWallet
	ugw, err = l.svcCtx.UserGameWalletModel.FindOneByUidProviderIdMoneyType(l.ctx, in.Uid, in.ProviderId, in.MoneyType)
	if err != nil && err != wallet.ErrNotFound {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, xerr.NewGrpcErrCodeMsg(xerr.DbError, fmt.Sprintf("find user transfer stat err:%v", err))
	}

	err = l.svcCtx.UserWalletModel.Trans(l.ctx, func(ctx context.Context, tx sqlx.Session) error {
		// 更新用户转账状态
		if ugw == nil {
			ugw = &wallet.UserGameWallet{
				Uid:         in.Uid,
				MoneyType:   in.MoneyType,
				MoneyAmount: 0,
				ProviderId:  in.ProviderId,
				State:       dbkey.Enable,
			}
			_, err2 := l.svcCtx.UserGameWalletModel.InsertTrans(ctx, tx, ugw)
			if err2 != nil {
				l.Logger.Errorf("err == ", zap.Error(err2))
				return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
			}
		}
		// 创建用户转入流水
		_, err2 := l.svcCtx.UserTransferToGameFlowModel.InsertTrans(ctx, tx, &utf)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		// 更新用户钱包余额
		err2 = l.svcCtx.UserWalletModel.DecrAmountTrans(ctx, tx, iOutMoneyAmount, uw.Id, in.Uid, in.MoneyType)
		if err2 != nil {
			l.Logger.Errorf("err == ", zap.Error(err2))
			return xerr.NewGrpcErrCodeMsg(xerr.DbError, err2.Error())
		}
		return nil
	})
	if err != nil {
		l.Logger.Errorf("err == ", zap.Error(err))
		return nil, nil
	}

	var rsp pb.UserCreateTransferToGameResp
	rsp.FlowNo = utf.FlowNo
	rsp.MoneyType = utf.MoneyType
	rsp.MoneyAmount = dOutMoneyAmount.Div(decimal.NewFromInt(walletkey.MoneyScale)).StringFixedBank(2)
	rsp.Balance = dUwMoneyAmount.Sub(dOutMoneyAmount).Div(decimal.NewFromInt(walletkey.MoneyScale)).StringFixedBank(2)
	return &rsp, nil
}
